home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
filesyst
/
dosfs
/
dmsdosfs.000
/
dmsdosfs
/
dmsdosfs-0.6.9b
/
dmsdos_dec.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-29
|
8KB
|
295 lines
/*
linux/fs/dmsdos/dmsdos_dec.c
DMSDOS filesystem: decompression routines
******************************************************************************
DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
written 1995,1996 by Frank Gockel
(C) Copyright 1995,1996 by Frank Gockel
Some code of the dmsdos filesystem has been copied from the msdos filesystem
so there are the following additional copyrights:
(C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
(C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
(C) Copyright 1992-1995 by Linus Torvalds
The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
The DMSDOS filesystem is distributed under the Gnu General Public Licence.
See file COPYING for details.
******************************************************************************
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include <linux/msdos_fs.h>
#include <linux/dmsdos_fs.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
extern Dblsb dblsb[];
/* cluster caching...has to be reprogrammed (?)
disabled due to multiple read problems
(besides, I did not notice any speedup)
unsigned char* ldc=NULL;
int ldc_cvfnr;
int ldc_cnr;
*/
/* known compression methods */
/* see header file */
/* some functions are inline for speed reasons - this eats kernel memory */
inline int getbit(unsigned char*clusterk,int*mask,int*count)
{ int ret;
ret=(*mask)&clusterk[*count];
(*mask)<<=1;
if(*mask==256)
{ *mask=1;
(*count)++;
}
return ret;
}
int getbits(unsigned char*clusterk,int*mask,int*count,int bits)
{ int orwert=1;
int ret=0;
int i;
for(i=0;i<bits;++i)
{ if(getbit(clusterk,mask,count))ret|=orwert;
orwert<<=1;
}
return ret;
}
int getDX(unsigned char*clusterk,int*mask,int*count)
{ if(!getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,6);
if(!getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,8)+64;
return getbits(clusterk,mask,count,12)+320;
}
int getCX(unsigned char*clusterk,int*mask,int*count)
{ if(getbit(clusterk,mask,count)) return 3;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,1)+4;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,2)+6;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,3)+10;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,4)+18;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,5)+34;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,6)+66;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,7)+130;
if(getbit(clusterk,mask,count)) return getbits(clusterk,mask,count,8)+258;
return -1;
}
int decrb(unsigned char*clusterk,int*mask,int*count,
unsigned char*clusterd,int*pos,int*sek,int dx,int k)
{ int i,cx;
if(dx==0)return -2;
if(dx==0x113f)
{ /*printk("DMSDOS: decrb: 0x113f sync found.\n");*/
(*sek)--;
if(*sek==0)return -1;
if(*pos%SECTOR_SIZE) return -2;
return 0;
}
cx=getCX(clusterk,mask,count)+k;
if(cx<=0)return -2;
if(dx>*pos) return -2;
for(i=0;i<cx;i++)clusterd[(*pos)+i]=clusterd[(*pos)+i-dx];
(*pos)+=cx;
return 0;
}
/* decompress a compressed cluster clusterk to clusterd */
int decompress(unsigned char*clusterd, unsigned char*clusterk,
Mdfat_entry*mde)
{
int sekcount;
int r,count,mask,pos,dx;
/*printk("DMSDOS: decompress: mdfatval=%d\n",mdfatval);*/
sekcount=mde->size_hi_minus_1+1;
count=0;
mask=1;
pos=0;
switch(getbits(clusterk,&mask,&count,32))
{
case DS_0_0:
case DS_0_1:
case DS_0_2:
/*printk("DMSDOS: decompressing DS-0-x\n");*/
do
{ r=0;
if(!getbit(clusterk,&mask,&count))
{ if(getbit(clusterk,&mask,&count))
{ clusterd[pos++]=getbits(clusterk,&mask,&count,7);
}
else
{ dx=getbits(clusterk,&mask,&count,6);
r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,-1);
}
}
else
{ if(!getbit(clusterk,&mask,&count))
{ clusterd[pos++]=getbits(clusterk,&mask,&count,7)|128;
}
else
{ dx=(!getbit(clusterk,&mask,&count)) ?
getbits(clusterk,&mask,&count,8)+64 :
getbits(clusterk,&mask,&count,12)+320;
r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,-1);
}
}
}
while(r==0);
if(r==-2)
{ printk("DMSDOS: error in DS-0-x compressed data.\n");
return -2;
}
/*printk("DMSDOS: decompress finished.\n");*/
return 0;
case JM_0_0:
case JM_0_1:
/*printk("DMSDOS: decompressing JM-0-x\n");*/
do
{ r=0;
if(!getbit(clusterk,&mask,&count))
{ clusterd[pos++]=getbits(clusterk,&mask,&count,7);
}
else
{ if(!getbit(clusterk,&mask,&count))
{ dx=getDX(clusterk,&mask,&count);
r=decrb(clusterk,&mask,&count,clusterd,&pos,&sekcount,dx,0);
}
else
{ clusterd[pos++]=getbits(clusterk,&mask,&count,7)|128;
}
}
}
while(r==0);
if(r==-2)
{ printk("DMSDOS: error in JM-0-x compressed data.\n");
return -2;
}
/*printk("DMSDOS: decompress finished.\n");*/
return 0;
case SQ_0_0:
printk("DMSDOS: Sorry, SQ-0-0 compression not yet supported.\n");
return -1;
default:
printk("DMSDOS: compression method not recognized.\n");
return -1;
} /* end switch */
return 0;
}
/* read a complete file cluster and decompress it if necessary;
currently only called by dmsdos_file_read;
do not use to read directory clusters (for speed reasons);
this function is unable to read cluster 0 (CVF root directory) */
int dmsdos_read_cluster(struct super_block*sb,
unsigned char*clusterd, int clusternr,int cvfnr)
{ Mdfat_entry mde;
unsigned char*clusterk;
int anz_sektoren;
int i;
struct buffer_head*bh;
int membytes;
int sektor;
/*int fullsize;*/
LOCK_READWRITE;
/*printk("DMSDOS: read_cluster %d in CVF %d\n",clusternr,cvfnr+1);*/
dbl_mdfat_value(sb,clusternr,cvfnr,NULL,&mde);
if((mde.flags&2)==0)
{ /* hmm, cluster is unused (it's a lost or ghost cluster)
and contains undefined data, but it *is* readable */
printk("DMSDOS: lost cluster %d in CVF %d detected\n",clusternr,
cvfnr+1);
UNLOCK_READWRITE;
return 0;
}
sektor=mde.sector_minus_1+1;
anz_sektoren=mde.size_lo_minus_1+1;/* real sectors on disk */
if(anz_sektoren>dblsb[cvfnr].s_sectperclust)
{ printk("DMSDOS: read_cluster: mdfat sektors > sectperclust, cutting\n");
anz_sektoren=dblsb[cvfnr].s_sectperclust;
}
if(mde.flags&1)
{ /* cluster is not compressed */
for(i=0;i<anz_sektoren;++i)
{ bh=read_dbl_sector(sb,sektor+i,cvfnr);
if(bh==NULL){UNLOCK_READWRITE;return -EIO;}
memcpy(&clusterd[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
bh_free(sb,bh);
}
}
else
{ /* cluster is compressed */
membytes=SECTOR_SIZE*anz_sektoren;
clusterk=(unsigned char*)MALLOC(membytes);
if(clusterk==NULL)
{ printk("DMSDOS: no memory for decompression!\n");
UNLOCK_READWRITE;
return -2;
}
for(i=0;i<anz_sektoren;++i)
{ bh=read_dbl_sector(sb,sektor+i,cvfnr);
if(bh==NULL)
{ FREE(clusterk);
UNLOCK_READWRITE;
return -EIO;
}
memcpy(&clusterk[i*SECTOR_SIZE],bh->b_data,SECTOR_SIZE);
bh_free(sb,bh);
}
i=decompress(clusterd,clusterk,&mde);
FREE(clusterk);
if(i)
{ printk("DMSDOS: decompression of cluster %d in CVF %d failed.\n",
clusternr,cvfnr+1);
UNLOCK_READWRITE;
return i;
}
}
UNLOCK_READWRITE;
return 0;
}